using UnityEngine;
using TMPro; // 引入 TextMeshPro 的命名空间，用于显示 UI 文本

// 定义一个名为 FrameRateCounter 的 MonoBehaviour 类，用于实时显示帧率或每帧耗时
public class FrameRateCounter : MonoBehaviour
{

	// 序列化字段，允许在 Inspector 面板中拖拽赋值，用于显示帧率/时间的 TextMeshProUGUI 组件
	[SerializeField]
	TextMeshProUGUI display;

	// 枚举类型，定义显示模式：可以显示 FPS（每秒帧数）或者 MS（每帧毫秒数）
	public enum DisplayMode { FPS, MS }

	// 当前的显示模式，默认为 FPS
	[SerializeField]
	DisplayMode displayMode = DisplayMode.FPS;

	// 序列化且可调节的字段，用于设置采样时间间隔，范围从 0.1 秒到 2 秒，默认 1 秒
	[SerializeField, Range(0.1f, 2f)]
	float sampleDuration = 1f;

	// 用于统计当前采样周期内的总帧数
	int frames;

	// 当前采样周期内累计的所有帧的时间总和（单位：秒）
	float duration,
		  // 采样期间遇到的单帧最短耗时（最优性能）
		  bestDuration = float.MaxValue,
		  // 采样期间遇到的单帧最长耗时（最差性能）
		  worstDuration;

	// 每一帧调用一次的 Unity 生命周期函数
	void Update()
	{
		// 获取当前帧的持续时间（未受 Time.timeScale 影响，适合做性能统计）
		float frameDuration = Time.unscaledDeltaTime;

		// 当前帧计数 +1
		frames += 1;

		// 累加这一帧的时间到总持续时间中
		duration += frameDuration;

		// 判断当前帧耗时是否为采样期内最佳（最小）帧耗时，如果是则更新
		if (frameDuration < bestDuration)
		{
			bestDuration = frameDuration;
		}

		// 判断当前帧耗时是否为采样期内最差（最大）帧耗时，如果是则更新
		if (frameDuration > worstDuration)
		{
			worstDuration = frameDuration;
		}

		// 当累计时间超过或等于我们设定的采样时长时，更新 UI 显示并重置统计
		if (duration >= sampleDuration)
		{
			if (displayMode == DisplayMode.FPS)
			{
				// 如果当前模式是 FPS（每秒帧数），则显示以下三行内容：
				// 第1行：最佳帧率（1 / 最短帧耗时）
				// 第2行：平均帧率（总帧数 / 总时间）
				// 第3行：最差帧率（1 / 最长帧耗时）
				display.SetText(
					"FPS\n{0:0}\n{1:0}\n{2:0}",
					1f / bestDuration,          // 最佳帧率（最高 FPS）
					frames / duration,          // 平均帧率
					1f / worstDuration          // 最差帧率（最低 FPS）
				);
			}
			else
			{
				// 如果当前模式是 MS（毫秒），则显示以下三行内容：
				// 第1行：最佳帧耗时（最短帧时间 * 1000，单位毫秒）
				// 第2行：平均帧耗时（总时间 / 总帧数 * 1000，单位毫秒）
				// 第3行：最差帧耗时（最长帧时间 * 1000，单位毫秒）
				display.SetText(
					"MS\n{0:1}\n{1:1}\n{2:1}",
					1000f * bestDuration,       // 最佳帧耗时（最低耗时，毫秒）
					1000f * duration / frames,  // 平均帧耗时（毫秒）
					1000f * worstDuration       // 最差帧耗时（最高耗时，毫秒）
				);
			}

			// 重置帧数计数器，准备下一个采样周期
			frames = 0;

			// 重置累计时间，准备下一个采样周期
			duration = 0f;

			// 重置最佳帧耗时为最大值，以便下一轮重新比较
			bestDuration = float.MaxValue;

			// ⚠️ 注意：这里将 worstDuration 重置为 0，而不是 float.MinValue，
			// 是为了确保第一帧就能正确比较并记录最差耗时。
			// 但如果你的采样周期内只有一帧，且你不希望它被误认为“最差”，也可以考虑初始化为一个极大值。
			worstDuration = 0f;
		}
	}
}